﻿#define DEBUG
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Net;
using System.Net.Sockets;
using System.Threading.Tasks;
using System.Configuration;
using CloudReader.Net;
using MySql.Data.MySqlClient;
using CloudReader.Net.Server;
using CloudReader.Net.Protocol;

namespace CloudReader.Server.Core
{
    public class ServerBackEnd
    {
        static CloudReaderServer server;
        static List<Connection> WaitQueue;//等待队列
        static List<Connection> ConnectionPool;//连接池
        static Parser parser;
        static MySqlConnection _conn;
        static string _connStr;
        static string _table;

        public int CurrentConnection { get => ConnectionPool.Count; }
        public int CurrentAvaliableConnection { get => TotalAvaliableConnection - CurrentConnection; }
        public int TotalAvaliableConnection { get; set; }

        public ServerBackEnd()
        {
            TotalAvaliableConnection = int.Parse(ConfigurationManager.AppSettings["MaxConnection"]);
            server = new CloudReaderServer();
            server.OnNewConnection += new Action<SocketAsyncEventArgs>(Connect);
            server.OnNewExceptionRaised += new Action<Exception>(Exception);
            server.OnNewPackageReceive += new Action<SocketAsyncEventArgs, CloudReaderPackage>(Receive);
            server.OnConnectionClose += new Action<Connection>(CloseConnection);
            server.Start(TotalAvaliableConnection);
            MySqlConnectionStringBuilder build = new MySqlConnectionStringBuilder()
            {
                Database = ConfigurationManager.AppSettings["Database"],
                Server = ConfigurationManager.AppSettings["Server"],
                UserID = ConfigurationManager.AppSettings["User"],
                Password = ConfigurationManager.AppSettings["Password"],
                CharacterSet = ConfigurationManager.AppSettings["Charset"],
                Pooling=true
            };
            _table = ConfigurationManager.AppSettings["Table"];
            _connStr = build.ConnectionString;
            Init();
        }

        void Init()
        {
            WaitQueue = new List<Connection>();
            ConnectionPool = new List<Connection>();
            parser = new Parser();
            _conn = new MySqlConnection(_connStr);
            _conn.Open();
            EventPool = new Queue<string>();
            ExceptionPool = new Queue<string>();
            Task t = new Task(new Action(Deamon));
            t.Start();
        }

        void Connect(SocketAsyncEventArgs e)
        {
            var c = e.UserToken as Connection;
            var s = c.Connect;
            //绑定注册函数
            c.ReadEventArgs.Completed += new EventHandler<SocketAsyncEventArgs>(OnValidate);
            var ttt = $"{DateTime.Now.ToString()}\t用户={c.Connect.RemoteEndPoint.ToString()}连接";
            EventPool.Enqueue(ttt);
            OnNewConnection?.Invoke(ttt);
            if (!s.ReceiveAsync(c.ReadEventArgs))
            {
                OnValidate(null, c.ReadEventArgs);
            }
            //添加到等待队列，以备守护进程检测
            WaitQueue.Add(c);
        }

        void OnValidate(object sender, SocketAsyncEventArgs e)
        {
            Task t = new Task(new Action<object>(Validate), e);
            t.Start();
        }
        void Validate(object o)
        {
            var e = o as SocketAsyncEventArgs;
            switch (e.LastOperation)
            {
                case SocketAsyncOperation.Receive:
                    {
                        var c = e.UserToken as Connection;
                        if (e.SocketError == SocketError.Success && e.BytesTransferred > 0)
                        {
                            var s = c.Connect;
                            if (s.Connected)
                            {
                                var data = new byte[e.BytesTransferred];
                                Array.Copy(e.Buffer, e.Offset, data, 0, data.Length);
                                var p = Parser.Decode(data);
                                //加密解密请放在Parse类中
                                var uid = p.Data.Split('_');
                                if (uid.Length < 2)
                                {
                                    return;
                                }
                                else
                                {
                                    Query(uid[0], uid[1], c);
                                    Response(c.isLogin, c);
                                }
                            }
                            else
                            {
                                WaitQueue.Remove(c);
                                server.Disconnect(c);
                            }
                        }
                        else
                        {
                            WaitQueue.Remove(c);
                            server.Disconnect(c);
                        }
                        break;
                    }
            }
        }
        void Query(string user, string password, Connection c)
        {
            var QueryString = $"SELECT id FROM {_table} WHERE username = '{user}' and password='{password}'";

            var com = new MySqlCommand(QueryString, _conn);
            try
            {
                var reader = com.ExecuteReader();
                while (reader.Read())
                {
                    if (reader.HasRows)
                    {
                        c.isLogin = true;
                        c.Uid = reader.GetInt32("id").ToString();
                    }
                    else
                    {
                        c.isLogin = false;
                    }
                }
                reader.Close();
            }
            catch (MySqlException e)
            {
                throw e;
            }
            finally
            {
                com.Dispose();
            }
        }
        void Response(bool login, Connection c)
        {
            CloudReaderPackage p;
            if (login)
            {
                p = parser["1", true];
                c.ReadEventArgs.Completed -= OnValidate;
                c.ReadEventArgs.Completed += new EventHandler<SocketAsyncEventArgs>(server.IOCPCompleted);
                if (c.Connect.ReceiveAsync(c.ReadEventArgs))
                {
                    //同步方法
                }
                ConnectionPool.Add(c);
                WaitQueue.Remove(c);

                var ttt = $"{DateTime.Now.ToString()}\t用户={c.Uid}:{c.Connect.RemoteEndPoint.ToString()}登录";
                EventPool.Enqueue(ttt);
                OnLoginSuccess?.Invoke(ttt);
                var data = Parser.Encode(p);
                c.WriteEventArgs.SetBuffer(data, 0, data.Length);
                c.Connect.SendAsync(c.WriteEventArgs);
            }
            else
            {
                p = parser["0", true];
                var data = Parser.Encode(p);
                c.WriteEventArgs.SetBuffer(data, 0, data.Length);
                c.Connect.SendAsync(c.WriteEventArgs);
            }
        }

        void Exception(Exception e)
        {
            ExceptionPool.Enqueue(e.Message);
            OnException?.Invoke(e.Message);
        }

        void Receive(SocketAsyncEventArgs e, CloudReaderPackage p)
        {
            var c = e.UserToken as Connection;
            switch (p.Type)
            {
                case CloudReaderProtocolType.Message:
                    {
                        foreach (var i in ConnectionPool)
                        {
                            lock (i)
                            {
                                var data = Parser.Encode(p);
                                if (!i.ReadEventArgs.Equals(e))
                                {
                                    i.WriteEventArgs.SetBuffer(data, 0, data.Length);
                                    i.Connect.SendAsync(i.WriteEventArgs);
                                }
                            }
                        }
                        break;
                    }
                case CloudReaderProtocolType.Broadcast:
                    {
                        foreach (var i in ConnectionPool)
                        {
                            lock (i)
                            {
                                var data = Parser.Encode(p);

                                i.WriteEventArgs.SetBuffer(data, 0, data.Length);
                                i.Connect.SendAsync(i.WriteEventArgs);

                            }
                        }
                        break;
                    }
                case CloudReaderProtocolType.PeerMessage:
                    {

                        break;
                    }
            }
        }

        async void Deamon()
        {
            while (server.isServerAlive)
            {
                for (int i = 0; i < ConnectionPool.Count; i++)
                {
                    if ((DateTime.Now - ConnectionPool[i].ActiveTime).Seconds >= 60)
                    {
                        lock (ConnectionPool)
                        {
                            server.Disconnect(ConnectionPool[i]);
                        }
                    }
                }
                await Task.Delay(5000);
            }
        }

        void CloseConnection(Connection e)
        {            
            ConnectionPool.Remove(e);
            var ttt = $"{DateTime.Now.ToString()}\t用户退出";
            EventPool.Enqueue(ttt);
            OnLogout?.Invoke(ttt);
        }

        //
        //      外部接口
        //
        public event Action<string> OnLoginSuccess;
        public event Action<string> OnLogout;
        public event Action<string> OnNewConnection;
        public event Action<string> OnException;
        public Queue<string> EventPool { get; set; }
        public Queue<string> ExceptionPool { get; set; }

        //
        //      性能监视
        //
    }
}
